import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import IA.Energia.Central;
import IA.Energia.Cliente;
import aima.search.framework.Successor;
import aima.search.framework.SuccessorFunction;

public class EnergiaSuccessor implements SuccessorFunction {
	public static long copiados = 0;
	static boolean cambiar = true;
	static boolean quitar = true;
	static boolean anadir = true;
	static boolean intercambiar = true;
	
	public EnergiaSuccessor() {
		cambiar = true;
		quitar = true;
		anadir = true;
		intercambiar = true;
	}
	
	public EnergiaSuccessor(boolean sicambiar, boolean siquitar, boolean sianadir,
			boolean siintercambiar) {
		cambiar = sicambiar;
		quitar = siquitar;
		anadir = sianadir;
		intercambiar = siintercambiar;
	}

	/* Devolvemos los sucesores encontrados por quitar clientes de centrales,
	 * anadir los clientes a centrales i mover los clientes de una central a otra
	 * Descripcion: Recorremos todos los clientes y, si se puden quitar de la central 
	 * a la que estan, generamos un estado que es una copia del principal, quitamos el 
	 * cliente de la central a la que esta y anadimos el estado a la lista. 
	 * Tambien para cada uno miramos si lo podemos poner o canviar de central 
	 * recorriendo todas las centrales y si se puede generemos un estado que es 
	 * una copia del principal, ponemos el cliente a la central y anadimos 
	 * el estado a la lista
	 */
	@Override
	public List getSuccessors(Object arg0) {
		
		Estado ES = (Estado) arg0; 
		List successors = new ArrayList();
		EnergiaHeuristica EH = new EnergiaHeuristica();
		//Obtenemos los datos del estado
		HashMap<Cliente, Central> clientes_aux = ES.get_clientes();
		HashMap<Central, CentralConClientes> centrales_aux = ES.get_centrales();
		
		Iterator<Entry<Cliente, Central>> itr = clientes_aux.entrySet().iterator();
		while(itr.hasNext()) {

			Entry<Cliente, Central> e = (Entry<Cliente, Central>)itr.next();
			boolean asignado;
			// Miramos si el cliente tiene central
			if(clientes_aux.get(e.getKey()) != null) asignado = true;
			else asignado = false;
			
			if(asignado) {
				// Si tiene central generamos un sucesor quitando el cliente de la central
				if(quitar && ES.can_remove(e.getKey())) {
					Estado CP = EstadoCopy (ES);
					CP.Quitar(e.getKey());
					successors.add(new Successor("Quitar cliente " + EH.getHeuristicValue(CP),CP));
				}
			}
			
			Iterator<Entry<Cliente, Central>> itrcli2 = clientes_aux.entrySet().iterator();
			while(itrcli2.hasNext()) {
				Entry<Cliente, Central> cli = (Entry<Cliente, Central>)itrcli2.next();
				if (intercambiar && ES.canSwap(e.getKey(), cli.getKey())) {
					Estado CP = EstadoCopy (ES);
					CP.Intercambiar(e.getKey(), cli.getKey());
					successors.add(new Successor("Intercambiar cliente " + EH.getHeuristicValue(CP),CP));
				}
			}
			
			// Recorremos las centrales por cada cliente
			Iterator<Entry<Central, CentralConClientes>> itc = centrales_aux.entrySet().iterator();
			while(itc.hasNext()) {
				
				Entry<Central, CentralConClientes> e2 = (Entry<Central, CentralConClientes>)itc.next();
				
				if(asignado) {
					// Si el cliente tiene central y la central candidata no es la misma
					// que la que tiene y se pude cambiar, se cambia y se anade el sucesor 
					// a la lista
					if(cambiar && (clientes_aux.get(e.getKey()) != e2.getKey()) &&
				       ES.canChange(e.getKey(),clientes_aux.get(e.getKey()),e2.getKey())) {
						
						Estado CP2 = EstadoCopy (ES);
						CP2.Mover(e.getKey(),clientes_aux.get(e.getKey()),e2.getKey());
						successors.add(new Successor("Mover cliente " + EH.getHeuristicValue(CP2),CP2));
						
					}
				}
				else {
					// Si el cliente no tiene central y se pude anadir el cliente a la central
					// candidata, se cambia y se anade el sucesor a la lista
					if(anadir && ES.can_put(e.getKey(),e2.getKey())){
						Estado CP3 = EstadoCopy (ES);
						CP3.Poner(e.getKey(),e2.getKey());	
						successors.add(new Successor("Anadir cliente " + EH.getHeuristicValue(CP3),CP3));
					}
				}
			}
		}

		return successors;
	}
	
	// Devuelve un nuevo estado que es una copia del anterior
	private Estado EstadoCopy (Estado est) {
		copiados++;
		//System.out.println("Estados copiados: " + copiados);
		Estado newEst = new Estado(est);
		return newEst;
	}
}
